package jmine.tec.hydra.send.impl.mq;

import java.io.IOException;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.NamingException;

import jmine.tec.hydra.HydraController;
import jmine.tec.hydra.HydraMessages;
import jmine.tec.hydra.api.HydraMessage;
import jmine.tec.hydra.domain.senderRegistry.MQSenderRegistry;
import jmine.tec.hydra.exception.HydraException;
import jmine.tec.hydra.send.Sender;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * @author piercio
 */
public class MQSender implements Sender {

    private static final Log LOG = LogFactory.getLog(MQSender.class);

    private Context jndiContext;

    private final MQSenderRegistry senderRegistry;

    /**
     * Construtor.
     * 
     * @param senderRegistry o registro de envio de MQ
     */
    public MQSender(MQSenderRegistry senderRegistry) {
        this.senderRegistry = senderRegistry;
    }

    /**
     * Envia uma mensagem para uma fila jms.
     * 
     * @param message a mensagem a ser enviada.
     */
    public void send(HydraMessage message) {
        this.jndiContext = ((HydraController) this.senderRegistry.getController()).getJmsSenderContext();
        QueueConnectionFactory connectionFactory;
        Queue targetQueue = null;
        try {
            targetQueue = this.getQueue(this.senderRegistry.getQueue());
            connectionFactory = this.getQueueConnectionFactory(this.senderRegistry.getQueueConnectionFactory());
        } catch (NamingException e) {
            throw new HydraException(HydraMessages.UNABLE_TO_SEND.create(targetQueue), e);
        }

        QueueConnection queueConnection = null;
        try {
            queueConnection = connectionFactory.createQueueConnection();
            QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
            QueueSender queueSender = queueSession.createSender(targetQueue);
            queueSender.send(this.createMessage(message, queueSession));
        } catch (JMSException e) {
            throw new HydraException(HydraMessages.UNABLE_TO_SEND.create(targetQueue), e);
        } catch (IOException e) {
            throw new HydraException(HydraMessages.UNABLE_TO_SEND.create(targetQueue), e);
        } finally {
            if (queueConnection != null) {
                try {
                    queueConnection.close();
                } catch (JMSException e) {
                    LOG.error("Não foi possível fechar a conexão JMS após envio de mensagem: " + e.getMessage(), e);
                }
            }
        }

    }

    /**
     * Devolve a fila JMS.
     * 
     * @param queueName o nome da fila.
     * @return a fila JMS.
     * @throws NamingException se não encontrar o queueName.
     */
    private Queue getQueue(String queueName) throws NamingException {
        return (Queue) this.jndiContext.lookup(queueName);
    }

    /**
     * Devolve o factory de QueueConnection.
     * 
     * @param connectionFactoryName o nome a connectionFactory.
     * @return o factory de QueueConnection.
     * @throws NamingException se não encontrar o connectionfactory.
     */
    private QueueConnectionFactory getQueueConnectionFactory(String connectionFactoryName) throws NamingException {
        return (QueueConnectionFactory) this.jndiContext.lookup(connectionFactoryName);
    }

    /**
     * Cria uma mensagem de FeederFile baseada no bean
     * 
     * @param message o bean contendo as informações necessárias para criar a mensagem.
     * @param session a sessão da fila.
     * @return a mensagem a ser enviada para fila JMS.
     * @throws JMSException caso ocorra algum erro durante a criação da mensagem.
     * @throws IOException IOException
     */
    private Message createMessage(HydraMessage message, Session session) throws JMSException, IOException {
        // TODO lundberg encoding do extmessage, e mesmo tipo de mensagem, deveria ser parametrizável.
        TextMessage textMessage = session.createTextMessage(message.getBodyAsString("UTF-8"));
        textMessage.setStringProperty("JMS_IBM_Format", "MQSTR   ");
        return textMessage;
    }
}
